package cn.zhyjohn.paysystem.utils;
 
import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageConfig;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PathVariable;
 
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Path;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
 
/**
 * @Classname CodeUtil
 * @Description TODO 二维码工具类
 * @Date 2019/7/10 19:49
 * @Created by JTJ
 */
public class CodeUtils {
 
    public static int width = 600;
    public static int height = 600;
    public static String format = "png";
 
    public static String contents = "默认内容";
 
    public static String defaultFilePath = "";
 
    public static String[] checkList = new String[] {"png","jpg","gif","jepg"};
 
    /**
     * @Title: createLogoAndCode
     * @Desc: 创建二维码
     * @param logo contents path
     * @return
     */
    public static String createLogoAndCode(File logo, String contents, String path) {
        String result = "success";
        if (contents!=null) {
            CodeUtils.contents = contents;
        }
        if(!checkFormat(logo)) {
            return "logo文件出错!";
        }
        // 生成二维码
        try {
            BitMatrix bitMatrix = new MultiFormatWriter().encode(contents, BarcodeFormat.QR_CODE, width, height,
                    setCodeParams());
            if(path!=null) {
                //生成文件路径
                Path filePath = new File(savePalce(path)).toPath();
                MatrixToImageWriter.writeToPath(bitMatrix, format, filePath);
            }
            MatrixToImageConfig matrixToImageConfig = new MatrixToImageConfig(0xFF000001, 0xFFFFFFFF);
            /* 添加logo图片
             *  问题：生成二维码正常,生成带logo的二维码logo变成黑白
             *  原因：MatrixToImageConfig默认黑白，需要设置BLACK、WHITE
             *  解决：https://ququjioulai.iteye.com/blog/2254382
             */
            //判断是否需要logo
            if(logo!=null) {
                BufferedImage bufferedImage = groupImage(MatrixToImageWriter.toBufferedImage(bitMatrix,matrixToImageConfig),logo);
                //生成图片文件
                ImageIO.write(bufferedImage, format, new File(defaultFilePath));
            }else {
                ImageIO.write(MatrixToImageWriter.toBufferedImage(bitMatrix,matrixToImageConfig), format, new File(defaultFilePath));
            }
        } catch (Exception e) {
            result = "生成二维码出错！"+e.toString();
        }
        return result;
    }
 
    /**
     * 绘制logo图片
     * @param matrixImage
     * @param logoFile
     * @return
     * @throws IOException
     */
    public static BufferedImage groupImage(BufferedImage matrixImage, File logoFile) throws IOException {
        //先读取二维码图片
 
        Graphics2D g = matrixImage.createGraphics();
 
        //再读取logo图片
        BufferedImage logoImage = ImageIO.read(logoFile);
 
        //设置logo大小，太大，会覆盖二维码，此处20%
        int logoWidth = logoImage.getWidth() > matrixImage.getWidth()*2 /10 ? (matrixImage.getWidth()*2 /10) : logoImage.getWidth();
        int logoHeight = logoImage.getHeight() > matrixImage.getHeight()*2 /10 ? (matrixImage.getHeight()*2 /10) : logoImage.getHeight();
 
        //设置logo图片放置位置  放在中心
        int x = (matrixImage.getWidth() - logoWidth) / 2;
        int y = (matrixImage.getHeight() - logoHeight) / 2;
 
        //开始合并绘制图片
        g.drawImage(logoImage, x, y, logoWidth, logoHeight, null);
        g.drawRoundRect(x, y, logoWidth, logoHeight, 15 ,15);
        //线条设置
        BasicStroke stroke = new BasicStroke(5,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
        g.setStroke(stroke);
 
        //logo边框颜色
        g.setColor(Color.WHITE);
        g.drawRect(x, y, logoWidth, logoHeight);
        //释放对象
        g.dispose();
        logoImage.flush();
        matrixImage.flush();
        return matrixImage;
    }
 
    /**
     * @Title: setCodeParams
     * @Desc: 设置二维码参数
     * @param
     * @return
     */
    public static HashMap<EncodeHintType, Object> setCodeParams() {
        // 封装二维码的参数
        HashMap<EncodeHintType, Object> hashMap = new HashMap<>();
        hashMap.put(EncodeHintType.CHARACTER_SET, "UTF-8"); // 字符集
        hashMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M); // 纠错等级
        hashMap.put(EncodeHintType.MARGIN, 2); // 边距
        return hashMap;
    }
 
    /**
     * @Title: savePalce
     * @Desc: 二维码保存地址
     * @param
     * @return
     */
    public static String savePalce(String path) {
        String codeName = UUID.randomUUID().toString() + new SimpleDateFormat("YYYY-MM-DD").format(new Date()).replace("-", "s");
        defaultFilePath = path + codeName.trim() + "." + format;
        return defaultFilePath;
    }
 
    /**
     * @Title: readCode
     * @Desc: 读取二维码信息
     * @param file
     * @return
     */
    public static String readCode(File file) {
        String result = "";
        try {
            MultiFormatReader formatReader = new MultiFormatReader();
 
            BufferedImage image = ImageIO.read(file);
 
            BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(new BufferedImageLuminanceSource(image)));
 
            Map<DecodeHintType, Object> hints = new HashMap<>();
            hints.put(DecodeHintType.CHARACTER_SET, "utf-8");// 字符集
            Result decodeResult = formatReader.decode(binaryBitmap, hints);
 
            result = "解析之后的结果:" + decodeResult.toString() + "\n" + "二维码格式类型:" + decodeResult.getBarcodeFormat() + "\n"
                    + "二维码文本内容:" + decodeResult.getText() + "!";
        } catch (Exception e) {
            result = "解析错误";
            return result;
        }
        return result;
    }
 
    /**
     * @Title: checkFormat
     * @Desc: 验证文件后缀格式
     * @param logoFile
     * @return
     */
    public static boolean checkFormat(File logoFile) {
        //文件是否为空
        if (null == logoFile) {
            System.out.println("logo文件为空!");
            return true;
        }
 
        String fileName = logoFile.getName();
        String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);
 
        for (String s : checkList) {
            if (s.equalsIgnoreCase(suffix)) {
                return true;
            }
        }
        return false;
    }
 
    /**
     * 实现 流文件 响应给浏览器
     * @param content
     * @param response
     */
    public static void encodeQrcode(@PathVariable("content") String content, HttpServletResponse response) {
        if (StringUtils.isEmpty(content))        return;
        MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
        Map hints = new HashMap();
        //设置字符集编码类型
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        //设置二维码四周的白色边框 ,默认是4,默认为4的时候白色边框实在是太粗了
        hints.put(EncodeHintType.MARGIN, 0);
        BitMatrix bitMatrix = null;
        try {
            bitMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, 190, 190, hints);
            BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix);
            //输出二维码图片流
            try {
                OutputStream out = response.getOutputStream();
                response.setContentType("image/png");
                //为文件重新设置名字，采用数据库内存储的文件名称
                response.addHeader("Content-Disposition", "attachment; filename=\"" + new String("code.png".getBytes("UTF-8"),"ISO8859-1") + "\"");
                ImageIO.write(image, "png", out);
                out.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (WriterException e1) {
            e1.printStackTrace();
        }
    }
}